package cn.sangyy.car.service.impl;

import cn.sangyy.basic.constent.BaseConstants;
import cn.sangyy.basic.exception.BusinessException;
import cn.sangyy.car.domain.CarType;
import cn.sangyy.car.mapper.CarTypeMapper;
import cn.sangyy.car.service.ICarTypeService;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author sangyangyang
 * @since 2023-05-25
 */
@Service
public class CarTypeServiceImpl extends ServiceImpl<CarTypeMapper, CarType> implements ICarTypeService {

    @Autowired
    private CarTypeMapper carTypeMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public List<CarType> tree(long l) {
        Object o = redisTemplate.opsForValue().get(BaseConstants.CAR_TYPE_TREE_IN_REDIS);
        if(Objects.nonNull(o)){
            return (List<CarType>) o;
        }
        //获取全局锁 集群模式下
        RLock lock = redissonClient.getLock(BaseConstants.CAR_TYPE_TREE_IN_REDIS);
        try {
            lock.lock();
            //在高并发的情况下可能有多个请求redis 等待的请求访问缓存有则直接返回，就不用再去访问数据库了
            o = redisTemplate.opsForValue().get(BaseConstants.CAR_TYPE_TREE_IN_REDIS);
            if(Objects.nonNull(o)){
                return (List<CarType>) o;
            }
            List<CarType> carTypeTree = getCarTree(l);
            if(carTypeTree.size() > 0){
                redisTemplate.opsForValue().set(BaseConstants.CAR_TYPE_TREE_IN_REDIS,carTypeTree);
            }else {
                carTypeTree = new ArrayList<>();
            }
            return carTypeTree;
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        } finally {
            if(lock != null){
                lock.unlock();
            }
        }
    }

    @Override
    public List<CarType> getChildren(Long pid) {
        return carTypeMapper.selectList(new EntityWrapper<CarType>().eq("pid", pid));
    }

    private List<CarType> getCarTree(Long pid){
        //方案一递归查 数据库压力大
/*        EntityWrapper<CarType> wrapper = new EntityWrapper<>();
        wrapper.eq("pid",l);
        List<CarType> typeList = carTypeMapper.selectList(wrapper);
        if(typeList != null && typeList.size() > 0){
            for (CarType carType : typeList) {
                Long id = carType.getId();
                if(id != 0){
                    List<CarType> children = tree(id);
                    carType.setChildren(children);
                }
            }
        }*/
        //方案二 查所有 循环再赋值
        List<CarType> typeList = carTypeMapper.selectList(null);
        Map<Long,CarType> map = new HashMap<>();
        typeList.forEach(c -> {
            map.put(c.getId(),c);
        });
        ArrayList<CarType> result = new ArrayList<>();
        typeList.forEach(c -> {
            if(Objects.equals(c.getPid(), pid)){
                result.add(c);
            }else {
                CarType parent = map.get(c.getPid());
                if(parent != null){
                    parent.getChildren().add(c);
                }
            }
        });
        return result;
    }

    @Override
    public boolean deleteById(Serializable id) {
        List<CarType> carTypes = getCarTree((Long) id);
        ArrayList<Long> ids = new ArrayList<>();
        ids.add((Long) id);
        getChildrenIds(carTypes,ids);
        Integer i = carTypeMapper.deleteBatch(ids);
        delayDoubleDelete();
        return true;
    }

    @Override
    public boolean insert(CarType entity) {
        boolean b = super.insert(entity);
        //延迟双删保证数据一致性
        delayDoubleDelete();
        return b;
    }

    @Override
    public boolean updateById(CarType entity) {
        boolean b = super.updateById(entity);
        delayDoubleDelete();
        return b;
    }

    /**
    * @author Sangyy
    * 延迟双删
    */
    public void delayDoubleDelete(){
        redisTemplate.delete(BaseConstants.CAR_TYPE_TREE_IN_REDIS);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        redisTemplate.delete(BaseConstants.CAR_TYPE_TREE_IN_REDIS);
    }

    private void getChildrenIds(List<CarType> carTypes,ArrayList<Long> ids){
        carTypes.forEach(c -> {
            ids.add(c.getId());
            List<CarType> children = c.getChildren();
            if(children.size() > 0){
                getChildrenIds(children,ids);
            }
        });
    }
}
